﻿using System;
using System.Collections.Generic;
using System.Linq;
using Diploma.Models.IRepositories;

namespace Diploma.Models.Repositories
{
    internal class GlobalTasksRepository : IGlobalTasksRepository
    {
        private readonly DiplomaEntities dataContext;

        public GlobalTasksRepository(DiplomaEntities dataContext)
        {
            this.dataContext = dataContext;
        }

        public GlobalTask GetGlobalTask(Guid id)
        {
            return
                dataContext.CheckPoints.OfType<GlobalTask>().Where(
                    gt => gt.CheckPointId == id && gt.DeletionDate == null).FirstOrDefault();
        }

        public Dictionary<PlaningType, List<GlobalTask>> GroupGlobalTasksByType(QualificationLevel level)
        {
            IOrderedEnumerable<GlobalTask> tasks =
                level.GlobalTasks.Where(gt => gt.DeletionDate == null).OrderBy(t => t.StartDate);
            IEnumerable<IGrouping<PlaningType, GlobalTask>> grouped = from t in tasks
                                                                      group t by t.PlaningType
                                                                      into g
                                                                      select g;
            Dictionary<PlaningType, List<GlobalTask>> v = grouped.ToDictionary(g => g.Key, g => g.ToList());
            return v;
        }

        public void TrimTasksAfterLastGlobalTask()
        {
        }

        public void RemoveGlobalTaskRemoveFromSequance(GlobalTask globalTask)
        {
            GlobalTask nextGlobalTask =
                globalTask.NextCheckPoints.OfType<GlobalTask>().Where(gt => gt.DeletionDate == null).OrderBy(
                    gt => gt.StartDate).FirstOrDefault();

            if (nextGlobalTask != null)
            {
                nextGlobalTask.PrevCheckPoint = globalTask.PrevCheckPoint;

                foreach (Task task in globalTask.Tasks.Where(t => t.DeletionDate == null).ToList())
                {
                    task.GlobalTask = nextGlobalTask;
                }
            }

            globalTask.PrevCheckPointId = null;
        }

        public void InsertGlobalTaskInSequance(GlobalTask globalTask)
        {
            IOrderedQueryable<GlobalTask> nextGlobalTasks = dataContext.CheckPoints.OfType<GlobalTask>().Where(
                gt => gt.PlaningTypeId == globalTask.PlaningTypeId &&
                      gt.QualificationLevelId == globalTask.QualificationLevelId &&
                      gt.StartDate > globalTask.StartDate &&
                      gt.DeletionDate == null).OrderBy(gt => gt.StartDate); 

            if (nextGlobalTasks.Count() != 0)
            {
                GlobalTask firstNextGlobalTask = nextGlobalTasks.Where(t => t.DeletionDate == null).FirstOrDefault();
                Guid? temp = firstNextGlobalTask.PrevCheckPointId;

                firstNextGlobalTask.PrevCheckPointId = globalTask.CheckPointId;
                globalTask.PrevCheckPointId = temp;
                foreach (
                    Task task in
                        firstNextGlobalTask.Tasks.Where(
                            t => t.StartDate < globalTask.StartDate && t.DeletionDate == null).ToList())
                {
                    task.GlobalTask = globalTask;
                }
                foreach (GlobalTask gt in nextGlobalTasks)
                {
                    gt.GlobalTasksCompletions.Clear();
                }
            }
            else
            {
                GlobalTask prevGlobalTask = dataContext.CheckPoints.OfType<GlobalTask>().Where(
                    gt => gt.QualificationLevelId == globalTask.QualificationLevelId &&
                          gt.PlaningTypeId == globalTask.PlaningTypeId &&
                          gt.StartDate < globalTask.StartDate &&
                          gt.DeletionDate == null).OrderByDescending(gt => gt.StartDate).FirstOrDefault();
                if (prevGlobalTask != null)
                {
                    globalTask.PrevCheckPoint = prevGlobalTask;
                }
            }
        }

        public void Add(GlobalTask globalTask)
        {
            globalTask.CheckPointId = Guid.NewGuid();

            InsertGlobalTaskInSequance(globalTask);

            dataContext.CheckPoints.AddObject(globalTask);
            dataContext.SaveChanges();
        }

        public void Edit(GlobalTask globalTask)
        {
            GlobalTask oldGlobalTask = GetGlobalTask(globalTask.CheckPointId);
            if (oldGlobalTask == null)
                throw new Exception();

            oldGlobalTask.Name = globalTask.Name;
            oldGlobalTask.StartDate = globalTask.StartDate;
            oldGlobalTask.Description = globalTask.Description;
            oldGlobalTask.RemindInDays = globalTask.RemindInDays;
            oldGlobalTask.CanStatusByLecturerEditing = globalTask.CanStatusByLecturerEditing;
            

            RemoveGlobalTaskRemoveFromSequance(oldGlobalTask);

            oldGlobalTask.PlaningType =
                dataContext.PlaningTypes.Where(pt => pt.PlaningTypeId == globalTask.PlaningTypeId).FirstOrDefault();
            oldGlobalTask.QualificationLevel =
                dataContext.QualificationLevels.Where(ql => ql.QualificationLevelId == globalTask.QualificationLevelId)
                    .FirstOrDefault();

            InsertGlobalTaskInSequance(oldGlobalTask);

            foreach (Task task in oldGlobalTask.Tasks.Where(t => t.DeletionDate == null))
            {
                if (task.GlobalTaskId == oldGlobalTask.CheckPointId && task.StartDate > oldGlobalTask.StartDate)
                    task.MarkForDeletion();
            }

            dataContext.SaveChanges();
        }

        public void Delete(GlobalTask globalTask)
        {
            RemoveGlobalTaskRemoveFromSequance(globalTask);

            globalTask.MarkForDeletion();

            //_dataContext.DeleteObject(globalTask);
            dataContext.SaveChanges();
        }

        public IEnumerable<GlobalTask> GetGlobalTaskByLevelAndPlaningType(int levelId, int planingTypeId, DateTime date)
        {
            return dataContext.CheckPoints.OfType<GlobalTask>().Where(
                gt => gt.QualificationLevelId == levelId &&
                      gt.PlaningTypeId == planingTypeId &&
                      gt.StartDate < date &&
                      gt.DeletionDate == null);
        }

        public IEnumerable<GlobalTask> GetGlobalTaskByLevelAndPlaningType(int levelId, int planingTypeId)
        {
            return dataContext.CheckPoints.OfType<GlobalTask>().Where(
                gt => gt.QualificationLevelId == levelId &&
                      gt.PlaningTypeId == planingTypeId &&
                      gt.DeletionDate == null);
        }

        public void SetCompletion(GlobalTask globalTask, Student student, bool? isCompleted)
        {
            GlobalTasksCompletion completion = dataContext.GlobalTasksCompletions.Where(
                c => c.StudentId == student.UserId &&
                     c.GlobalTaskId == globalTask.CheckPointId &&
                     c.DeletionDate == null).FirstOrDefault();
            
            if (completion == null)
            {
                var newCompletion = new GlobalTasksCompletion
                                        {
                                            Student = student,
                                            GlobalTask = globalTask,
                                            CompletionDate = DateTime.Today,
                                            IsComplete = isCompleted ?? false,
                                        };
                dataContext.AddToGlobalTasksCompletions(newCompletion);
                
            }

            else
            {
                completion.IsComplete = isCompleted ?? false;
                completion.CompletionDate = DateTime.Today;
                
            }
            dataContext.SaveChanges();
        }

        public void SetCompletionDate(GlobalTask globalTask)
        {
            globalTask.EndDate = DateTime.Today;
            dataContext.SaveChanges();
        }

        public bool GlobalTaskCanBeAdded(GlobalTask globalTask)
        {
            IQueryable<GlobalTask> globalTasks = dataContext.CheckPoints.OfType<GlobalTask>().Where(gt =>
                                                                                                     gt.PlaningTypeId ==
                                                                                                     globalTask.
                                                                                                         PlaningTypeId &&
                                                                                                     gt.
                                                                                                         QualificationLevelId ==
                                                                                                     globalTask.
                                                                                                         QualificationLevelId &&
                                                                                                     gt.StartDate ==
                                                                                                     globalTask.
                                                                                                         StartDate &&
                                                                                                     gt.DeletionDate ==
                                                                                                     null);
            bool taskWithSameDateExist = dataContext.CheckPoints.OfType<Task>().Where(t =>
                                                                                                    t.GlobalTask.PlaningTypeId ==
                                                                                                    globalTask.PlaningTypeId &&
                                                                                                    t.GlobalTask.QualificationLevelId ==
                                                                                                    globalTask.
                                                                                                        QualificationLevelId &&
                                                                                                    t.StartDate ==
                                                                                                    globalTask.StartDate &&
                                                                                                    t.DeletionDate ==
                                                                                                    null).Count() != 0;
            if (globalTasks.Count() == 1 && globalTasks.First().CheckPointId == globalTask.CheckPointId)
                return true;
            if (taskWithSameDateExist)
                return false;
            return globalTasks.Count() == 0;
        }

        public IEnumerable<GlobalTask> GetNextTasks(GlobalTask globalTask)
        {
            return globalTask.NextCheckPoints.OfType<GlobalTask>().Where(gt => gt.DeletionDate == null);
        }
    }
}